package com.dev;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import com.log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
public class JavaIndentEditor extends BaseIndentEditor{
	//final static int segmentLength=1024;
	static Paint selectionbgcolor=new Paint();
	static int handledl;
	static int handleHeight;
	static int stringColor=0xffff0000;
	static int valueColor=0xffbbff00;
	static int keywordColor=0xff007fff;
	static int symbolColor=0xff0000ff;//emm
	static int commentColor=0xff007f00;
	static int autoHintColor=0x77888888;
	static int textColor=0xff000000;
	static int operator=0xff0000ff;
	static int baseType=0xffff00ff;
    static char[] OPERATOR;
	volatile StringBuilder text;
	volatile boolean handleOnShow=false;
	volatile InertiaScroll inertiaScroll;
	volatile AutoHideHandle ahh=null;
	volatile WaitLongClick wlc;
	volatile int scrollX;
	volatile int scrollY;
	int handleFitEdgeLim;
	int editorbgcolor;
	int baseline;
	int tablen;
	int lineHeight;
	int textSize;
	int scrollYMaximum;
	int scrollXMaximum;
	int lineNumberStart;
    int primex;
    int primey;
    int spaceAdvance;
	boolean showSpaceChar=true;
    boolean onTextChanged_ignoreChange=false;
	InputConnectionProxy icp;
	Paint handle=new Paint();
	Paint lineHighlight;
	Paint lineNumber=new Paint();
	ArrayList<TabSpan> tabs=new ArrayList<TabSpan>(1024);
	HashSet<String> words=new HashSet<String>();
    JavaEditorPage jep;
	public JavaIndentEditor(MainActivity ma){
		super(ma);
		selectionbgcolor.setColor(super.selectionbgcolor);
		setPadding((int)(6*ma.dp),8,0,0);
		textPaint.setTypeface(Typeface.MONOSPACE);
		letTextSize((int)ma.dp*ma.shr.getInt(GUISettings.NOTE_TEXT_SIZE,24));
		handle=new Paint();
		handle.setColor(0xff777f00);
		handledl=(int)(12*ma.dp);
		handleFitEdgeLim=(int)(40*ma.dp);
		lineHighlight=new Paint();
		lineHighlight.setColor(currentLineHighlight);
		if(words.isEmpty()){
			for(int index=0;index<WORDS.length;index++){
				words.add(WORDS[index]);
			}
		}
		if(OPERATOR==null){
			OPERATOR=new char[]{
				'[',']','(',')','+','-','*','%','{','}',
				'&','^','|','!','~',';','<','>','=','.',','
			};
			Arrays.sort(OPERATOR);
		}
	}
	final static String[] WORDS=new String[]{
		"switch","if","else","case","default","final","return","throw",
		"static","new","public","private","protected","synchronized",
		"instanceof","class","import","extends","interface","transient",
		"int","byte","char","short","long","double","native","try",
		"float","void","String","package","this","super","throws",
		"catch","volatile","while","null","implements","for","enum","do",
		"abstract","true","false","break"
	};
	final static String[] KEYWORDS=new String[]{
		"switch","if","else","case","default","final",
		"static","new","public","private","protected",
		"instanceof","class","import",
	};
	final static String[] BASE_TYPE=new String[]{
		"int","byte","char","short","long","double",
		"float","void","String",
	};
	@Override
	public void letTextSize(int textSize) {
		this.textSize=textSize;
		textPaint.setTextSize(textSize);
		lineHeight=textSize;
		baseline=(int)(lineHeight*0.84);
		tablen=(int)textPaint.measureText(tabWidth);
        spaceAdvance=(int)textPaint.measureText(Character.toString(' '));
		if(text!=null){
			letText(text);
		}
	}
	void atTextChanged(){
		tcv.againWait=true;
		tcv.interrupt();
		showCursor=true;
		invalidate();
		View tab=ma.gui.tfNow;
		if(tab instanceof JavaEditorTab){
			JavaEditorTab jet=(JavaEditorTab)tab;
			jet.canSave=true;
			jet.setTextColor(0xffff0000);
			ma.gui.ivSave.setColorFilter(null);
			ma.gui.ivSave.invalidate();
			ma.gui.ivRefresh.setColorFilter(null);
			ma.gui.ivRefresh.invalidate();
		}
	}
	public void showSelection(){
		int size=tabs.size();
		if(size>0){
			final int position=Math.max(selectionStart,selectionEnd);
			outmost:
			for(int index=size/2,a=0,b=size;;){
				int enter=tabs.get(index).start;
				if(position>enter){
					if(index+1==b){
						int yabove=primey+lineHeight*(index+2);
						int ybelow=yabove-getHeight()-lineHeight;
						if(scrollY>=yabove||scrollY<=ybelow){
							scrollY=primey+lineHeight*index;
							invalidate();
							return;
						}
						break;
					}else{
						int posWill=index+(b-index)/2+1;
						a=index+1;
						index=posWill;
					}
				}else if(position==enter){
					int yabove=primey+lineHeight*(index+1);
					int ybelow=yabove-getHeight()-lineHeight;
					if(scrollY>=yabove||scrollY<=ybelow){
						scrollY=primey+lineHeight*index;
						invalidate();
					}
					return;
				}else{
					if(index==a){
						int yabove=primey+lineHeight*(index+1);
						int ybelow=yabove-getHeight()-lineHeight;
						if(scrollY>=yabove||scrollY<=ybelow){
							scrollY=primey+lineHeight*index;
							invalidate();
						}
						return;
					}else{
						int posWill=index-(index-a)/2-1;
						b=index;
						index=posWill;
					}
				}
			}
		}else{
			return;
		}
	}
	public void letText(StringBuilder text){
		this.text=text;
		int len=text.length();
		tabs.clear();
		TabSpan ts=new TabSpan(0);
		tabs.add(ts);
		if(selectionStart>=len){
			selectionStart=len;
		}
		if(selectionEnd>=len){
			selectionEnd=len;
		}
		outmost:
		for(int index=0;index<len;index++){
			char ch=text.charAt(index);
			if(ch=='\n'){
				String sub=text.substring(ts.start,index+1);
				ts.end=index+1;
				ts.string=sub;
				ts.width=textPaint.measureText(sub);
				ts=new TabSpan(index+1);
				tabs.add(ts);
			}else if(ch=='\t'){
				ts.tab++;
				int indexSaved=index;
				for(index++;index<len;index++){
					ch=text.charAt(index);
					if(ch=='\t'){
						ts.tab++;
					}else if(ch=='\n'){
						String sub=text.substring(ts.start,indexSaved);
						ts.string=sub;
						ts.end=index;
						ts.width=textPaint.measureText(sub);
						TabSpan next=new TabSpan(index);
						next.end=index+1;
						next.width=0;
						next.string="\n";
						ts.next=next;
						ts=new TabSpan(index+1);
						tabs.add(ts);
						break;
					}else{
                        if(ch==' '){
                            ts.spaceCount++;
                        }
						String sub=text.substring(ts.start,indexSaved);
						ts.string=sub;
						ts.end=index;
						ts.width=textPaint.measureText(sub);
						TabSpan next=new TabSpan(index);
						ts.next=next;
						ts=next;
						index--;
						break;
					}
				}
			}else if(ch=='/'){
				if(++index<len){
					ch=text.charAt(index);
					if(ch=='/'){
						String sub=text.substring(ts.start,index-1);
						ts.end=index-1;
						ts.string=sub;
						ts.width=textPaint.measureText(sub);
						TabSpan next=new TabSpan(index-1);
						next.textColor=commentColor;
						ts.next=next;
						ts=next;
						second:
						for(index++;index<len;index++){
							ch=text.charAt(index);
							if(ch=='\n'){
								sub=text.substring(ts.start,index+1);
								ts.end=index+1;
								ts.string=sub;
								ts.width=textPaint.measureText(sub);
								ts=new TabSpan(index+1);
								tabs.add(ts);
								break;
							}else if(ch=='\t'){
								ts.tab++;
								int indexSaved=index;
								for(index++;index<len;index++){
									ch=text.charAt(index);
									if(ch=='\t'){
										ts.tab++;
									}else if(ch=='\n'){
										sub=text.substring(ts.start,indexSaved);
										ts.end=index;
										ts.string=sub;
										ts.width=textPaint.measureText(sub);
										next=new TabSpan(index);
										next.end=index+1;
										next.string="\n";
										next.width=0;
										ts.next=next;
										ts=new TabSpan(index);
										tabs.add(ts);
										break second;
									}else{
                                        if(ch==' '){
                                            ts.spaceCount++;
                                        }
										sub=text.substring(ts.start,indexSaved);
										ts.end=index;
										ts.string=sub;
										ts.width=textPaint.measureText(sub);
										next=new TabSpan(index);
                                        next.textColor=commentColor;
										ts.next=next;
										ts=next;
                                        break;
									}
								}
							}else if(ch==' '){
                                ts.spaceCount++;
                            }
						}
					}else if(ch=='*'){
                        String sub=text.substring(ts.start,index-1);
                        ts.end=index-1;
                        ts.string=sub;
                        ts.width=textPaint.measureText(sub);
                        TabSpan next=new TabSpan(index-1);
                        next.textColor=commentColor;
                        ts.next=next;
						ts=next;
                        second:
                        for(index++;index<len;index++){
                            ch=text.charAt(index);
                            if(ch=='\n'){
                                sub=text.substring(ts.start,index+1);
                                ts.end=index+1;
                                ts.string=sub;
                                ts.width=textPaint.measureText(sub);
                                ts=new TabSpan(index+1);
                                ts.textColor=commentColor;
								tabs.add(ts);
                            }else if(ch=='\t'){
                                ts.tab++;
                                int indexSaved=index;
                                for(index++;index<len;index++){
                                    ch=text.charAt(index);
                                    if(ch=='\t'){
                                        ts.tab++;
                                    }else if(ch=='\n'){
                                        sub=text.substring(ts.start,indexSaved);
                                        ts.end=index;
                                        ts.string=sub;
                                        ts.width=textPaint.measureText(sub);
                                        next=new TabSpan(index);
                                        next.textColor=commentColor;
                                        next.end=index+1;
                                        next.string="\n";
                                        next.width=0;
                                        ts.next=next;
                                        ts=new TabSpan(index);
                                        ts.textColor=commentColor;
										tabs.add(ts);
                                        break;
                                    }else{
                                        if(ch==' '){
                                            ts.spaceCount++;
                                        }
                                        sub=text.substring(ts.start,indexSaved);
                                        ts.end=index;
                                        ts.string=sub;
                                        ts.width=textPaint.measureText(sub);
                                        next=new TabSpan(index);
                                        next.textColor=commentColor;
                                        ts.next=next;
                                        ts=next;
                                        break;
                                    }
                                }
                            }else if(ch==' '){
                                ts.spaceCount++;
                            }else if(ch=='*'){
                                if(++index<len){
                                    ch=text.charAt(index);
                                    if(ch=='/'){
                                        break second;
                                    }else{
                                        index--;
                                    }
                                }
                            }
                        }
                    }else if(ts.textColor!=operator){
						ts.end=index-1;
						String sub=text.substring(ts.start,index-1);
						ts.string=sub;
						ts.width=textPaint.measureText(sub);
						TabSpan next=new TabSpan(index-1);
						next.textColor=operator;
						ts.next=next;
						ts=next;
						index--;
					}else{
                        index--;
                    }
				}else if(ts.textColor!=operator){
                    ts.end=index-1;
                    String sub=text.substring(ts.start,index-1);
                    ts.string=sub;
                    ts.width=textPaint.measureText(sub);
                    TabSpan next=new TabSpan(index-1);
                    next.textColor=operator;
                    ts.next=next;
                    ts=next;
                }
			}else if(ch=='"'){
				if(ts.textColor!=stringColor){
					ts.end=index;
					String sub=text.substring(ts.start,index);
					ts.string=sub;
					ts.width=textPaint.measureText(sub);
					TabSpan next=new TabSpan(index);
					next.textColor=stringColor;
					ts.next=next;
					ts=next;
				}
				second:
				for(index++;index<len;index++){
					ch=text.charAt(index);
					if(ch=='"'){
						
						break;
					}else if(ch=='\\'){
						if(++index<len){
							ch=text.charAt(index);
							if(ch=='\t'){
								index--;
								continue;
							}else if(ch==' '){
                                ts.spaceCount++;
                            }else if(ch=='\n'){
                                index--;
                            }
						}else{break;}
					}else if(ch=='\t'){
						ts.tab++;
						int indexSaved=index;
						for(index++;index<len;index++){
							ch=text.charAt(index);
							if(ch=='\t'){
								ts.tab++;
							}else if(ch=='\n'){
								ts.end=index;
								String sub=text.substring(ts.start,indexSaved);
								ts.string=sub;
								ts.width=textPaint.measureText(sub);
								TabSpan next=new TabSpan(index);
								ts.next=next;
								ts=next;
								index--;
								break second;
							}else{
                                if(ch==' '){
                                    ts.spaceCount++;
                                }
								ts.end=index;
								String sub=text.substring(ts.start,indexSaved);
								ts.string=sub;
								ts.width=textPaint.measureText(sub);
								TabSpan next=new TabSpan(index);
								next.textColor=stringColor;
								ts.next=next;
								ts=next;
								index--;
								break;
							}
						}
					}else if(ch=='\n'){
						index--;break;
					}else if(ch==' '){
                        ts.spaceCount++;
                    }
				}
			}else if(ch=='\''){
				if(ts.textColor!=stringColor){
					ts.end=index;
					String sub=text.substring(ts.start,index);
					ts.string=sub;
					ts.width=textPaint.measureText(sub);
					TabSpan next=new TabSpan(index);
					next.textColor=stringColor;
					ts.next=next;
					ts=next;
				}
				second:
				for(index++;index<len;index++){
					ch=text.charAt(index);
					if(ch=='\''){
						ts.end=index+1;
						String sub=text.substring(ts.start,index+1);
						ts.string=sub;
						ts.width=textPaint.measureText(sub);
						TabSpan next=new TabSpan(index);
						next.textColor=stringColor;
						ts.next=next;
						ts=next;
						break;
					}else if(ch=='\\'){
						if(++index<len){
							ch=text.charAt(index);
							if(ch=='\t'){
								index--;
							}else if(ch==' '){
                                ts.spaceCount++;
                            }else if(ch=='\n'){
                                index--;
                            }
						}else{break;}
					}else if(ch=='\t'){
						ts.tab++;
						int indexSaved=index;
						for(index++;index<len;index++){
							ch=text.charAt(index);
							if(ch=='\t'){
								ts.tab++;
							}else if(ch=='\n'){
								ts.end=index;
								String sub=text.substring(ts.start,indexSaved);
								ts.string=sub;
								ts.width=textPaint.measureText(sub);
								TabSpan next=new TabSpan(index);
								ts.next=next;
								ts=next;
								index--;
								break second;
							}else{
								ts.end=index;
								String sub=text.substring(ts.start,indexSaved);
								ts.string=sub;
								ts.width=textPaint.measureText(sub);
								TabSpan next=new TabSpan(index);
								next.textColor=stringColor;
								ts.next=next;
								ts=next;
								index--;
								break;
							}
						}
					}else if(ch=='\n'){
						index--;break;
					}else if(ch==' '){
                        ts.spaceCount++;
                    }
				}
			}else if(ch==' '){
                ts.spaceCount++;
            }else if(Arrays.binarySearch(OPERATOR,ch)>=0){
				if(ts.textColor!=operator){
					String sub=text.substring(ts.start,index);
					ts.end=index;
					ts.string=sub;
					ts.width=textPaint.measureText(sub);
					TabSpan next=new TabSpan(index);
					next.textColor=operator;
					ts.next=next;
					ts=next;
				}
			}else if(Character.isLetter(ch)){
				int indexSaved=index;
				second:
				for(index++;index<len;index++){
                    if(index<len){
                        ch=text.charAt(index);
                        if(Character.isLetter(ch)){
                        }else{
                            String word=text.substring(indexSaved,index);
                            if(words.contains(word)){
                                if(ts.textColor!=keywordColor){
                                    ts.end=indexSaved;
                                    String sub=text.substring(ts.start,indexSaved);
                                    ts.string=sub;
                                    ts.width=textPaint.measureText(sub);
                                    TabSpan next=new TabSpan(indexSaved);
                                    next.textColor=keywordColor;
                                    ts.next=next;
                                    ts=next;
                                }
                            }else if(ts.textColor!=textColor){
                                ts.end=indexSaved;
                                String sub=text.substring(ts.start,indexSaved);
                                ts.string=sub;
                                ts.width=textPaint.measureText(sub);
                                TabSpan next=new TabSpan(indexSaved);
                                ts.next=next;
                                ts=next;
                            }
                            index--;
                            break;
                        }
                    }else{
                        String word=text.substring(indexSaved,index);
                        if(words.contains(word)){
                            if(ts.textColor!=keywordColor){
                                ts.end=indexSaved;
                                String sub=text.substring(ts.start,indexSaved);
                                ts.string=sub;
                                ts.width=textPaint.measureText(sub);
                                TabSpan next=new TabSpan(indexSaved);
                                next.textColor=keywordColor;
                                ts.next=next;
                                ts=next;
                            }
                        }else if(ts.textColor!=textColor){
                            ts.end=indexSaved;
                            String sub=text.substring(ts.start,indexSaved);
                            ts.string=sub;
                            ts.width=textPaint.measureText(sub);
                            TabSpan next=new TabSpan(indexSaved);
                            ts.next=next;
                            ts=next;
                        }
                        break;
                    }
				}
			}else{
				if(ts.textColor!=textColor){
					ts.end=index;
					String sub=text.substring(ts.start,index);
					ts.string=sub;
					ts.width=textPaint.measureText(sub);
					TabSpan next=new TabSpan(index);
					ts.next=next;
					ts=next;
				}
			}
		}
		String sub=text.substring(ts.start,len);
		ts.end=len;
		ts.string=sub;
		ts.width=textPaint.measureText(sub);
	}
	public void moveSelection(int a,int b){
		final int selectionStartWill=selectionStart+a;
		final int selectionEndWill=selectionEnd+b;
		int length=text.length();
		if(selectionStartWill>=0){
			if(selectionStartWill<=length){
				selectionStart=selectionStartWill;
			}else{
				selectionStart=length;
			}
		}else{
			selectionStart=0;
		}
		if(selectionEndWill>=0){
			if(selectionEndWill<=length){
				selectionEnd=selectionEndWill;
			}else{
				selectionEnd=length;
			}
		}else{
			selectionEnd=0;
		}
	}
    @Override
	public void letSelection(int n){
		if(text==null){
			selectionStart=0;
			selectionEnd=0;
		}else{
			if(n>=0&&n<=text.length()){
				selectionStart=n;
				selectionEnd=n;
				//invalidate();
			}else{
				log.alert("无效的参数","selection start:"+selectionStart+"\nselection end:"+selectionEnd);
			}
		}
	}
    @Override
	public void letSelection(int a,int b){
		if(text==null){
			selectionStart=0;
			selectionEnd=0;
			return;
		}
		int text_length=text.length();
		if(a<0){
			a=0;
			if(b<0){
				b=0;
			}else if(b>text_length){
				b=text_length;
			}
			selectionStart=a;
			selectionEnd=b;
		}else if(a>text_length){
			a=text_length;
			if(b<0){
				b=0;
			}else if(b>text_length){
				b=text_length;
			}
			selectionStart=a;
			selectionEnd=b;
		}else if(b<0){
			b=0;
			selectionStart=a;
			selectionEnd=b;
		}else if(b>text_length){
			b=text_length;
			selectionStart=a;
			selectionEnd=b;
		}else{
			selectionStart=a;
			selectionEnd=b;
		}
	}

    @Override
    public void commitText(String s) {
        int a=Math.min(selectionStart,selectionEnd);
        int b=Math.max(selectionStart,selectionEnd);
        if(s==null||s.isEmpty()){
            if(a!=b){
                text.delete(a,b);
                selectionEnd=selectionStart;
                letText(text);
                atTextChanged();
                invalidate();
            }
        }else if(a==b){
            text.insert(a,s);
            moveSelection(s.length(),s.length());
            letText(text);
            atTextChanged();
            invalidate();
        }else{
            text.replace(a,b,s);
            selectionEnd=b-(b-a)+s.length();
            letText(text);
            atTextChanged();
            invalidate();
        }
    }
	public int seeLineHeight(){
		return lineHeight;
	}
	void letLineHeight(int l){
		lineHeight=l;
	}
	int calculateClicked(int actionx,int actiony){
		int row=(actiony-primey)/lineHeight;
        int size=tabs.size();
        if(row>=size){
            return text.length();
        }else if(row>=0){
			TabSpan ts=tabs.get(row);
			int xx=primex;
			float lima=primex;
            outmost:
            for(;;){
                TabSpan next=ts.next;
                float[] fs;
                String string=ts.string;
                if(ts.fs==null){
                    fs=new float[string.length()];
                    textPaint.getTextWidths(string,fs);
                    ts.fs=fs;
                }else{
                    fs=ts.fs;
                }
                for(int index=0;;index++){
                    if(index<fs.length){
                        int limb=xx+(int)(fs[index]/2);
                        if(actionx>=lima&&actionx<limb){
                            return ts.start+index;
                        }
                        lima=limb;
                        xx+=fs[index];
                    }else{
                        int len=ts.end-ts.start;
                        for(;index<len;index++){
                            int xxWill=xx+tablen-(xx-primex)%tablen;
                            int limb=(xx+xxWill)/2;
                            if(actionx>=lima&&actionx<limb){
                                return ts.start+index;
                            }
                            lima=limb;
                            xx=xxWill;
                        }
                        break;
                    }
                }
                if(next==null){
                    return ts.end;
                }else{
                    ts=next;
                }
            }
		}
        return -1;
	}
	@Override
	public boolean dispatchKeyEvent(KeyEvent event){
		switch(event.getKeyCode()){
			/*case KeyEvent.KEYCODE_SHIFT_LEFT:
				return false
			case KeyEvent.KEYCODE_SHIFT_RIGHT:
				return false;*/
			case KeyEvent.KEYCODE_VOLUME_UP:
				return false;
			case KeyEvent.KEYCODE_VOLUME_DOWN:
				return false;
			case KeyEvent.KEYCODE_VOLUME_MUTE:
				return false;
			case KeyEvent.KEYCODE_POWER:
				return false;
			case KeyEvent.KEYCODE_TAB:
				if(event.getAction()==KeyEvent.ACTION_DOWN){
                    if(canEdit){
                        commitText("\t");
                    }
				}
				return true;
			case KeyEvent.KEYCODE_SPACE:
				if(event.getAction()==KeyEvent.ACTION_DOWN){
                    if(canEdit){
                        if(icp!=null)icp.commitText(" ",1);
                    }
				}
				return true;
			case KeyEvent.KEYCODE_DEL:
				if(event.getAction()==KeyEvent.ACTION_DOWN){
                    if(canEdit){
                        int a=selectionStart;
                        int b=selectionEnd;
                        //log.alert("del keyevent");
                        if(a==b){
                            if(a==0)return true;
                            text.delete(a-1,a);
                            letSelection(a-1);
                            atTextChanged();
                            invalidate();
                        }else{
                            text.delete(a,b);
                            atTextChanged();
                            if(a<b){
                                selectionStart=a;
                                selectionEnd=a;
                            }else{
                                selectionStart=b;
                                selectionEnd=b;
                            }
                        }
                    }
					
				}
				return true;
			case KeyEvent.KEYCODE_ENTER:
				if(event.getAction()==KeyEvent.ACTION_DOWN){
                    if(canEdit){
                        String s="\n";
                        int a=Math.min(selectionStart,selectionEnd);
                        int b=Math.max(selectionStart,selectionEnd);
                        for(int index=a-1;index>=0;index--){
                            char ch=text.charAt(index);
                            if(ch=='\n'){
                                for(index++;index<text.length();index++){
                                    ch=text.charAt(index);
                                    if(ch=='\t'){
                                        s+='\t';
                                    }else{
                                        break;
                                    }
                                }
                                break;
                            }
                        }
                        text.replace(a,b,s);
                        a+=s.length();
                        selectionStart=a;
                        selectionEnd=a;
                        atTextChanged();
                        showSelection();
                        invalidate();
                    }
				}
				return true;
			case KeyEvent.KEYCODE_DPAD_LEFT:
				if(event.getAction()==KeyEvent.ACTION_DOWN){
					if(selectionStart==selectionEnd){
						moveSelection(-1,-1);
					}else{
						moveSelection(0,-1);
					}
					showCursor=true;
					tcv.againWait=true;
					tcv.interrupt();
					invalidate();
				}
				return true;
			case KeyEvent.KEYCODE_DPAD_RIGHT:
				if(event.getAction()==KeyEvent.ACTION_DOWN){
					if(selectionStart==selectionEnd){
						moveSelection(1,1);
					}else{
						moveSelection(0,1);
					}
					showCursor=true;
					tcv.againWait=true;
					tcv.interrupt();
					invalidate();
				}
				return true;
			default:
				if(event.getAction()==KeyEvent.ACTION_DOWN){
					int uc=event.getUnicodeChar();
					if(uc>=0&&uc<0xffff){
						char ch=(char)uc;
						String s=Character.toString(ch);
						int l=(int)textPaint.measureText(s);
						if(l>0){
							if(icp!=null)icp.commitText(s,1);
						}
					}
				}
				return true;
		}
	}
	@Override
	protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
		super.onTextChanged(text, start, lengthBefore, lengthAfter);
		if(onTextChanged_ignoreChange){
			onTextChanged_ignoreChange=false;
			return;
		}
		String s=text.toString();
		if(s.length()>0){
			atTextChanged();
			icp.commitText(s,1);
			onTextChanged_ignoreChange=true;
			setText("");
		}
	}
	@Override
	public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
		InputConnection inputConnection= super.onCreateInputConnection(outAttrs);
		icp=new InputConnectionProxy(inputConnection);
		return icp;
	}
	@Override
	protected void onVisibilityChanged(View changedView,int visibility){
		super.onVisibilityChanged(changedView,visibility);
		if(visibility==View.VISIBLE){
			if(hasFocus()){
				tcv.finished=true;
				tcv=new TurnCursorVisibility();
				tcv.start();
			}else{
				tcv.finished=true;
				tcv.interrupt();
				showCursor=true;
				invalidate();
			}
		}else{
			tcv.finished=true;
			tcv.interrupt();
		}
	}
	@Override
	protected void onFocusChanged(boolean gainFocus,int direction,Rect previouslyFocusedRect){
		super.onFocusChanged(gainFocus,direction,previouslyFocusedRect);
		if(hasFocus()){
			tcv.finished=true;
			tcv=new TurnCursorVisibility();
			tcv.start();
		}else{
			tcv.finished=true;
			if(!showCursor){
				showCursor=true;
				invalidate();
			}
		}
	}
	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		editorbgcolor=ma.shr.getInt("code_editor_bgcolor",defaultbgcolor);
		primex=getPaddingLeft()+lineHeight*2;
		primey=getPaddingTop();
		lineNumberStart=getPaddingLeft();
	}
	@Override
	public void draw(Canvas canvas) {
		if(text==null){
			int textSize=(int)(30*ma.dp);
			textPaint.setTextSize(textSize);
			textPaint.setColor(0x7f7f7f7f);
			canvas.drawText("Null",primex,primey+textSize,textPaint);
		}else{
			int vw=getWidth();
			int vh=getHeight();
			int yupper=scrollY+vh-1;
			int xupper=scrollX+vw-1;
			int startLine=(scrollY-primey)/lineHeight;
			int startx=primex;
			int starty=primey+lineHeight*startLine;
			int cursorWidth=Math.round(textPaint.getTextSize()/13);if(cursorWidth<=0)cursorWidth=1;
			Paint cursor=new Paint();cursor.setStrokeWidth(cursorWidth);
			int size=tabs.size();
			int dotSize=(int)(lineHeight*0.3);
			scrollYMaximum=tabs.size()*lineHeight+primey;
			scrollXMaximum=0;
			if(startLine<size){
			}else return;
			canvas.translate(-scrollX,-scrollY);
			textPaint.setTextSize(textSize);
			int jx=(int)((baseline-(0.75*baseline))/2+(baseline*0.8));
			int line=startLine+1;
			lineNumber.setTextSize(textPaint.getTextSize()*0.75f);
            int endline=(scrollY+vh-primey)/lineHeight+1;
            drawLineBackground:
            for(int a=startLine,b=endline<size?endline:size;;){
                if(a<b){
                    int mid=a+(b-a)/2;
                    int offs=tabs.get(mid).start;
                    if(selectionStart<offs){
                        b=mid;
                        if(a==b)break;
                    }else{
                        if(mid+1<size){
                            a=mid+1;
                            offs=tabs.get(mid+1).start;
                            if(selectionStart<offs){
                                int t=mid*lineHeight+primey;
                                canvas.drawRect(scrollX,t,scrollX+vw,t+lineHeight,lineHighlight);
                                break;
                            }
                        }else{
                            int t=mid*lineHeight+primey;
                            canvas.drawRect(scrollX,t,scrollX+vw,t+lineHeight,lineHighlight);
                            break;
                        }
                    }
                }else{
                    break;
                }
            }
			int tabIndex=startLine;
			drawText:
			for(;tabIndex<size;tabIndex++){
				TabSpan ts=tabs.get(tabIndex);
				canvas.drawText(String.format("%03d",line),lineNumberStart,starty+jx,lineNumber);
				for(;ts!=null;){
					TabSpan next=ts.next;
                    int startxWill=startx+(int)ts.width;
                    String string=ts.string;
					if(ts.tab>0)startxWill+=ts.tab*tablen-(startx-primex)%tablen;
					if(selectionStart>=ts.start){
						if(selectionStart<ts.end){
                            float[] fs;
                            if(ts.fs==null){
                                fs=new float[string.length()];
                                textPaint.getTextWidths(string,fs);
                                ts.fs=fs;
                            }else{
                                fs=ts.fs;
                            }
							if(selectionStart==selectionEnd){
								if(showCursor){
									int xx=startx;
                                    measure:
									for(int ii=0;;ii++){
										if(ii<fs.length){
											if(ts.start+ii==selectionEnd){
												canvas.drawLine(xx,starty,xx,starty+lineHeight,cursor);
												//canvas.drawRect(x,y,xx,y+lineHeight,selectionbgcolor);
												break;
											}
											xx+=fs[ii];
										}else{
											for(;;ii++){
												if(ts.start+ii==selectionEnd){
													canvas.drawLine(xx,starty,xx,starty+lineHeight,cursor);
													//canvas.drawRect(x,y,xx,y+lineHeight,selectionbgcolor);
													break;
												}
                                                xx+=tablen-(xx-primex)%tablen;
											}
											break;
										}
									}
								}
							}else if(selectionEnd<ts.end){
                                int a=Math.min(selectionStart,selectionEnd);
                                int b=Math.max(selectionStart,selectionEnd);
                                int xx=startx;
                                measure:
                                for(int ii=0;;ii++){
                                    if(ii<fs.length){
                                        if(ts.start+ii>=a){
                                            int xxSaved=xx;
                                            xx+=fs[ii];
                                            for(ii++;;ii++){
                                                if(ii<fs.length){
                                                    if(ts.start+ii==b){
                                                        canvas.drawRect(xxSaved,starty,xx,starty+lineHeight,selectionbgcolor);
                                                        break;
                                                    }
                                                    xx+=fs[ii];
                                                }else{
                                                    for(;;ii++){
                                                        if(ts.start+ii==b){
                                                            canvas.drawRect(xxSaved,starty,xx,starty+lineHeight,selectionbgcolor);
                                                            //canvas.drawRect(x,y,xx,y+lineHeight,selectionbgcolor);
                                                            break;
                                                        }
                                                        xx+=tablen-(xx-primex)%tablen;
                                                    }
                                                    break;
                                                }
                                            }
                                            break;
                                        }
                                        xx+=fs[ii];
                                    }else{
                                        for(;;ii++){
                                            if(ts.start+ii>=a){
                                                int xxSaved=xx;
                                                for(ii++;;ii++){
                                                    if(ts.start+ii==b){
                                                        canvas.drawRect(xxSaved,starty,xx,starty+lineHeight,selectionbgcolor);
                                                        break;
                                                    }
                                                }
                                                //canvas.drawRect(x,y,xx,y+lineHeight,selectionbgcolor);
                                                break;
                                            }
                                            xx+=tablen-(xx-primex)%tablen;
                                        }
                                        break;
                                    }
                                }
                            }else if(next==null){
                                int xx=startx;
                                measure:
                                for(int ii=0;;ii++){
                                    if(ii<fs.length){
                                        if(ts.start+ii==selectionStart){
                                            canvas.drawRect(xx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                                            break;
                                        }
                                        xx+=fs[ii];
                                    }else{
                                        for(;;ii++){
                                            if(ts.start+ii==selectionStart){
                                                canvas.drawRect(xx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                                                break;
                                            }
                                            xx+=tablen-(xx-primex)%tablen;
                                        }
                                        break;
                                    }
                                }
                            }else{
                                int xx=startx;
                                measure:
                                for(int ii=0;;ii++){
                                    if(ii<fs.length){
                                        if(ts.start+ii==selectionStart){
                                            canvas.drawRect(xx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                                            break;
                                        }
                                        xx+=fs[ii];
                                    }else{
                                        for(;;ii++){
                                            if(ts.start+ii==selectionStart){
                                                canvas.drawRect(xx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                                                break;
                                            }
                                            xx+=tablen-(xx-primex)%tablen;
                                        }
                                        break;
                                    }
                                }
                            }
						}else if(selectionEnd>=ts.start){
                            float[] fs;
                            if(ts.fs==null){
                                fs=new float[string.length()];
                                textPaint.getTextWidths(string,fs);
                                ts.fs=fs;
                            }else{
                                fs=ts.fs;
                            }
							if(selectionEnd<ts.end){
                                int xx=startx;
                                measure:
                                for(int ii=0;;ii++){
                                    if(ii<fs.length){
                                        if(ts.start+ii==selectionEnd){
                                            if(next==null){
                                                canvas.drawRect(xx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                                            }else{
                                                canvas.drawRect(xx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                                            }
                                            break;
                                        }
                                        xx+=fs[ii];
                                    }else{
                                        for(;;ii++){
                                            if(ts.start+ii==selectionEnd){
                                                if(next==null){
                                                    canvas.drawRect(xx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                                                }else{
                                                    canvas.drawRect(xx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                                                }
                                                break;
                                            }
                                            xx+=tablen-(xx-primex)%tablen;
                                        }
                                        break;
                                    }
                                }
								
							}else if(next==null){
                                if(selectionStart==ts.end){
                                    if(selectionEnd==ts.end){
                                        canvas.drawLine(startxWill,starty,startxWill,starty+lineHeight,cursor);
                                    }else{
                                        canvas.drawRect(startx,starty,scrollX+vw,starty+lineHeight,lineHighlight);
                                    }
                                }else if(selectionEnd==ts.end){
                                    canvas.drawRect(startx,starty,scrollX+vw,starty+lineHeight,lineHighlight);
                                }
                            }
						}else if(next==null){
                             canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                        }else{
                            canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                        }
					}else if(selectionEnd>ts.start){
						if(selectionEnd<ts.end){
							float[] fs;
							if(ts.fs==null){
								
								fs=new float[string.length()];
								textPaint.getTextWidths(string,fs);
								ts.fs=fs;
							}else{
								fs=ts.fs;
							}
							int xx=startx;
							for(int ii=0;;ii++){
								if(ii<fs.length){
									if(ts.start+ii==selectionEnd){
										canvas.drawRect(startx,starty,xx,starty+lineHeight,selectionbgcolor);
										break;
									}
                                    xx+=fs[ii];
								}else{
									for(;;ii++){
										if(ts.start+ii==selectionEnd){
											canvas.drawRect(startx,starty,xx,starty+lineHeight,selectionbgcolor);
											break;
										}
                                        xx+=tablen-(xx-primex)%tablen;
									}
									break;
								}
							}
						}else if(next==null){
							canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
						}else{
                            canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                        }
					}
                    if(ts.spaceCount>0&&showSpaceChar){
                        int[] spaces=ts.spaces;
                        if(ts.spaces==null){
                            spaces=new int[ts.spaceCount];
                            float[] fs;
                            if(ts.fs==null){
                                
                                fs=new float[string.length()];
                                textPaint.getTextWidths(string,fs);
                                ts.fs=fs;
                            }else{
                                fs=ts.fs;
                            }
                            int xx=0;
                            for(int index=0,offs=0;;index++){
                                if(index<fs.length){
                                    char ch=text.charAt(ts.start+index);
                                    if(ch==' '){
                                        spaces[offs]=xx;
                                        offs++;
                                    }
                                    xx+=fs[index];
                                }else{
                                    break;
                                }
                            }
                            ts.spaces=spaces;
                        }
                        textPaint.setColor(0x77888888);
                        for(int index=0,len=spaces.length;index<len;index++){
                            int i=spaces[index];
                            canvas.drawCircle(startx+i+spaceAdvance/2,starty+lineHeight/2,dotSize,textPaint);
                        }
                    }
					textPaint.setColor(ts.textColor);
					canvas.drawText(ts.string,startx,starty+baseline,textPaint);
                    startx=startxWill;
					if(startx>scrollXMaximum)scrollXMaximum=startx;
                    if(startx>xupper)break;
					ts=next;
				}
				starty+=lineHeight;
				if(starty>yupper)break;
				startx=primex;
				line++;
			}//outmost loop
		}
	}
	Point touchDown=new Point();
    Point touchDown2=null;
	Point scrollSaved=new Point();
	Point scrollSaved_touchSaved=new Point();
	long touchDownTime;
	long recentTouchTime;
	Point recentTouch=new Point();
	boolean fingerPressed=false;
	boolean scaleAction;
	int fingerMoved;
	int textSizeSaved;
	int touchCtrl;
    double distanceSaved;
	float speed;
	float fingerDistanceSaved;
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		int ex=(int)event.getX();
		int ey=(int)event.getY();
		int rx=(int)event.getRawX();
		int ry=(int)event.getRawY();
		switch(event.getAction()){
			case MotionEvent.ACTION_DOWN:
				touchDown.x=rx;
				touchDown.y=ry;
				touchDownTime=System.currentTimeMillis();
				fingerMoved=0;
				fingerPressed=true;
				if(wlc!=null)wlc.interrupt();
				if(inertiaScroll!=null)inertiaScroll.interrupt();
				wlc=new WaitLongClick();
				wlc.start();
				wlc.touch.x=ex;
				wlc.touch.y=ey;
				recentTouchTime=System.currentTimeMillis();
				recentTouch.x=ex;
				recentTouch.y=ey;
				touchCtrl=0;
				scrollSaved.x=scrollX;
				scrollSaved.y=scrollY;
				scrollSaved_touchSaved.x=rx;
				scrollSaved_touchSaved.y=ry;
				break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if(!scaleAction){
                    textSizeSaved=textSize;
                    int xx=(int)event.getX(1);
                    int yy=(int)event.getY(1);
                    touchDown2=new Point();
                    touchDown2.x=xx;
                    touchDown2.y=yy;
                    int a=Math.abs(ex-xx);
                    int b=Math.abs(ey-yy);
                    distanceSaved=(int)Math.sqrt(a*a+b*b);
                }
                break;
			case MotionEvent.ACTION_MOVE:
				if(event.getPointerCount()==1&&!scaleAction){
					if(fingerMoved==0){
						int dx=Math.abs(rx-touchDown.x);
						int dy=Math.abs(ry-touchDown.y);
						if(dx>fingerMovedLim||dy>fingerMovedLim){
                            wlc.interrupt();
							long dTime=System.currentTimeMillis()-recentTouchTime;
							if(dx>dy){
								fingerMoved=2;//水平移动
								if(dTime>0){
									speed=(rx-touchDown.x)/dTime;
								}
							}else if(dx<dy){//垂直移动
								//log.alert("ver");
								fingerMoved=1;
								if(dTime>0){
									speed=(ry-touchDown.y)/dTime;
								}
							}else{//方向不明
								fingerMoved=3;
							}
						}
					}else if(fingerMoved==1){
						int scrollyWill=scrollSaved.y-(ry-scrollSaved_touchSaved.y);
						//log.alert("scrolYMaximum:"+scrollYMaximum);
						if(scrollyWill<=0){
							scrollSaved.y=0;
							scrollSaved_touchSaved.y=ry;
							scrollY=0;
							invalidate();
						}else if(scrollyWill>=scrollYMaximum){
							scrollSaved.y=scrollYMaximum;
							scrollSaved_touchSaved.y=ry;
							scrollY=scrollYMaximum;
							invalidate();
						}else{
							scrollY=scrollyWill;
							invalidate();
						}
						long dTime=System.currentTimeMillis()-recentTouchTime;
						if(dTime>0){
							float fingerMovedSpeed_will=(ey-recentTouch.y)/dTime;
							speed=(fingerMovedSpeed_will+speed)/2;
						}
					}else if(fingerMoved==2){
                        int scrollxWill=scrollSaved.x-(rx-scrollSaved_touchSaved.x);
                        if(scrollxWill<=0){
                            scrollSaved.x=0;
                            scrollSaved_touchSaved.x=rx;
                            scrollX=0;
                            invalidate();
                        }else if(scrollxWill>=scrollXMaximum){
                            scrollSaved.x=scrollXMaximum;
                            scrollSaved_touchSaved.x=rx;
                            scrollX=scrollXMaximum;
                            invalidate();
                        }else{
                            scrollX=scrollxWill;
                            invalidate();
                        }
                        long dTime=System.currentTimeMillis()-recentTouchTime;
                        if(dTime>0){
                            float fingerMovedSpeed_will=(ex-recentTouch.x)/dTime;
                            speed=(fingerMovedSpeed_will+speed)/2;
                        }
                    }else{
                        int scrollxWill=scrollSaved.x-(rx-scrollSaved_touchSaved.x);
                        int scrollyWill=scrollSaved.y-(ry-scrollSaved_touchSaved.y);
                        if(scrollxWill<=0){
                            scrollSaved.x=0;
                            scrollSaved_touchSaved.x=rx;
                            if(scrollyWill<=0){
                                scrollSaved.y=0;
                                scrollSaved_touchSaved.y=ry;
                                scrollX=0;
                                scrollY=0;
                                invalidate();
                            }else if(scrollyWill>=scrollYMaximum){
                                scrollSaved.y=scrollYMaximum;
                                scrollSaved_touchSaved.y=ry;
                                scrollX=0;
                                scrollY=scrollYMaximum;
                                invalidate();
                            }else{
                                scrollX=scrollxWill;
                                scrollY=scrollyWill;
                                invalidate();
                            }
                        }else if(scrollxWill>=scrollXMaximum){
                            scrollSaved.x=scrollXMaximum;
                            scrollSaved_touchSaved.x=rx;
                            if(scrollyWill<=0){
                                scrollSaved.y=0;
                                scrollSaved_touchSaved.y=ry;
                                scrollX=scrollXMaximum;
                                scrollY=0;
                                invalidate();
                            }else if(scrollyWill>=scrollYMaximum){
                                scrollSaved.y=scrollYMaximum;
                                scrollSaved_touchSaved.y=ry;
                                scrollX=scrollXMaximum;
                                scrollY=scrollYMaximum;
                                invalidate();
                            }else{
                                scrollX=scrollXMaximum;
                                scrollY=scrollyWill;
                                invalidate();
                            }
                        }else if(scrollyWill<=0){
                            scrollSaved.y=0;
                            scrollSaved_touchSaved.y=ry;
                            scrollX=scrollxWill;
                            scrollY=0;
                            invalidate();
                        }else if(scrollyWill>=scrollYMaximum){
                            scrollSaved.y=scrollYMaximum;
                            scrollSaved_touchSaved.y=ry;
                            scrollX=scrollxWill;
                            scrollY=scrollYMaximum;
                            invalidate();
                        }else{
                            scrollX=scrollxWill;
                            scrollY=scrollyWill;
                            invalidate();
                        }
                    }
				}else {
                    int xx=(int)event.getX(1),yy=(int)event.getY(1);
                    if(scaleAction){
                        double distance=Math.sqrt(Math.abs(ex-xx)+Math.abs(ey-yy));
                        double rate=distance/distanceSaved;
                        int sizeWill=(int)(rate*textSizeSaved);
                        if(sizeWill<=maxTextSize){
                            if(sizeWill>=minTextSize){
                                letTextSize(sizeWill);
                            }else{
                                letTextSize(minTextSize);
                            }
                        }else{
                            letTextSize(maxTextSize);
                        }
                        invalidate();
                    }else{
                        int dx=Math.abs(touchDown2.x-xx);
                        int dy=Math.abs(touchDown2.y-yy);
                        if(dx>fingerMovedLim||dy>fingerMovedLim){
                            scaleAction=true;
                        }
                    }
                }
				/*if(!wlc.waited){
					wlc.lastTouch.x=ex;
					wlc.lastTouch.y=ey;
				}*/
				recentTouchTime=System.currentTimeMillis();
				recentTouch.x=ex;
				recentTouch.y=ey;
				break;
			case MotionEvent.ACTION_UP:
				fingerPressed=false;
				touchDown2=null;
				wlc.interrupt();
				if(fingerMoved!=0){
					inertiaScroll=new InertiaScroll();
					inertiaScroll.orientation=fingerMoved;
					inertiaScroll.initialSpeed=speed;
					inertiaScroll.initialScrollX=scrollX;
					inertiaScroll.initialScrollY=scrollY;
					inertiaScroll.start();
				}else{
					if(ma.gui.searchbar.getVisibility()!=VISIBLE){
						int titleIndex=ma.gui.titleIndex;
                        if(ma.gui.getChildAt(titleIndex)==ma.gui.batch){
                            ma.gui.removeViewAt(titleIndex);
                            ma.gui.addView(ma.gui.titlebar,titleIndex);
                        }
					}
					if(ex>=0&&ex<getWidth()&&ey>=0&&ey<getHeight()){
						if(isFocused()){
							if(canShowSoftInput)imm.showSoftInput(this,0);
							if(text!=null){
								int a=scrollX+ex;
								int b=scrollY+ey;
								int rr;
								rr=calculateClicked(a,b);
								if(rr>=0){
                                    //jep.status.setText("pos="+rr+",ch="+text.charAt(rr));
									letSelection(rr);
									showCursor=true;
									tcv.againWait=true;
									tcv.interrupt();
									handleOnShow=true;
									if(ahh==null){
										ahh=new AutoHideHandle();
										ahh.start();
									}else{
										ahh.interrupt();
										ahh=new AutoHideHandle();
										ahh.start();
									}
									invalidate();
								}
							}
						}else{
							if(requestFocus()){
								if(canShowSoftInput)imm.showSoftInput(this,0);
								if(text!=null){
									int a=scrollX+ex;
									int b=scrollY+ey;
									int rr;
									rr=calculateClicked(a,b);
									if(rr>=0){
										if(selectionStart<selectionEnd){
											if(rr>=selectionStart&&rr<selectionEnd){
											}else letSelection(rr);
										}else if(selectionStart>selectionEnd){
											if(rr>=selectionEnd&&rr<selectionStart){}else letSelection(rr);
										}else{letSelection(rr);}
										showCursor=true;
										tcv.againWait=true;
										tcv.interrupt();
										handleOnShow=true;
										if(ahh==null){
											ahh=new AutoHideHandle();
											ahh.start();
										}else{
											ahh.interrupt();
											ahh=new AutoHideHandle();
											ahh.start();
										}
										invalidate();
									}
								}
							}
						}
					}
				}
				break;
			case MotionEvent.ACTION_CANCEL:
				fingerPressed=false;
		}
		return true;
	}
	class AutoHideHandle extends Thread{
		@Override
		public void run(){
			try{
				sleep(800);
				handleOnShow=false;
				JavaIndentEditor.this.postInvalidate();
			}catch(InterruptedException e){
			}catch(Exception e){
				log.alert(e.toString());
			}
			super.run();
		}
	}
	class InputConnectionProxy extends  InputConnectionWrapper{
		InputConnection former;
		InputConnectionProxy(InputConnection former){
			super(former,false);
			this.former=former;
		}
		@Override
		public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
			return false;
		}
		@Override
		public boolean deleteSurroundingText(int beforeLength, int afterLength) {
            if(!canEdit)return false;
            if(beforeLength<0||afterLength<0)return false;
			int a=selectionStart;
			int b=selectionEnd;
			//log.alert("del surrounding");
			if(a<b){
				int start=a-beforeLength;
				int end=b;
				if(start<0){
                    text.delete(0,end);
                }else{
                    text.delete(start,end);
                }
                letSelection(start);
				end=start+afterLength;
                atTextChanged();
				if(end>text.length()){
                    text.delete(start,text.length());
                }else{
                    text.delete(start,end);
                }
                letText(text);
			}else if(a==b){
				int start=a-beforeLength;
				int end=a;
				if(start<0){
                    text.delete(0,end);
                }else{
                    text.delete(start,end);
                }
				letSelection(start);
				end=start+afterLength;
                atTextChanged();
				if(end>text.length()){
                    text.delete(start,text.length());
                }else{
                    text.delete(start,end);
                }
                letText(text);
			}else{
				int start=b-beforeLength;
				int end=b;
				if(start<0){
                    text.delete(0,end);
                }else{
                    text.delete(start,end);
                }
				letSelection(start);
				end=start+afterLength;
                atTextChanged();
				if(end>text.length()){
                    text.delete(start,text.length());
                }else{
                    text.delete(start,end);
                }
				letText(text);
			}
			tcv.againWait=true;
			showCursor=true;
			tcv.interrupt();
			invalidate();
			return true;
		}
		@Override
		public boolean sendKeyEvent(KeyEvent event) {
			return former.sendKeyEvent(event);
		}
		@Override
		public boolean commitText(CharSequence commit, int newCursorPosition) {
			int selectionA=Math.min(selectionStart,selectionEnd);
			//int selectionB=Math.max(selectionStart,selectionEnd);//text will replace with a and b
			String baseindent="";
			for(int index=selectionA-1;index>=0;index--){
				if(index>=0){
					char ch=text.charAt(index);
					if(ch=='\n'){
						for(index++;index<text.length();index++){
							ch=text.charAt(index);
							if(ch=='\t'){
								baseindent+='\t';
							}else break;
						}
						break;
					}
				}
			}
			StringBuilder commit_sb=new StringBuilder();
			outmost:
			for(int index=0,len=commit.length();index<len;index++){
				char ch=commit.charAt(index);
				if(ch=='\n'){
					commit_sb.append(ch);
					commit_sb.append(baseindent);
                    for(index++;index<len;index++){
                        ch=commit.charAt(index);
                        if(ch!='\t'){
                            index--;
                            break;
                        }
                    }
				}else{
					commit_sb.append(ch);
				}
			}
			text.replace(selectionStart,selectionEnd,commit_sb.toString());
			if(selectionStart<selectionEnd){
				selectionEnd=selectionStart+commit_sb.length();
				atTextChanged();
			}else if(selectionStart==selectionEnd){
				selectionEnd+=commit_sb.length();
				atTextChanged();
			}else{
                selectionStart=selectionEnd+commit_sb.length();
            }
			return true;
		}
	}
	public class TabSpan{
        int spaceCount;
		int tab;
		int textColor=JavaIndentEditor.this.textColor;
		int start;
		int end;
        int spaces[];
		float fs[];
		float width;
        String string;
        //ArrayList<Segment> string=new ArrayList<Segment>();
		TabSpan next;
		TabSpan(int start){
			this.start=start;
		}
	}
    public class Segment{
        String string;
        int width;
    }
	class InertiaScroll extends Thread{
		int orientation;
		double initialSpeed;
		double minSpeed=0.002;
		double inertia;
		int initialScrollX;
		int initialScrollY;
		InertiaScroll(){
			inertia=0.002;//(10*ma.dp)/1000;
		}
		@Override
		public void run(){
			super.run();
			long initialTime=System.currentTimeMillis();
			long dTime;
			if(orientation==2){
				int scrollXWill;
				int scrollXSaved=initialScrollX;
				if(initialSpeed<0){
					try{
						sleep(2);
					}catch(Exception e){}
					while(!interrupted()){
						dTime=System.currentTimeMillis()-initialTime;
						double speedNow=initialSpeed+inertia*dTime;
						if(speedNow<-minSpeed){
							scrollXWill=initialScrollX-(int)((initialSpeed+(inertia*dTime)/2)*dTime);
							if(scrollXWill>scrollXSaved){
								scrollX=scrollXWill;
								scrollY=initialScrollY;
								postInvalidate();
							}
							scrollXSaved=scrollXWill;
						}else{
							break;
						}
					}
				}else if(initialSpeed>0){
					try{
						sleep(2);
					}catch(Exception e){}
					while(!interrupted()){
						dTime=System.currentTimeMillis()-initialTime;
						double speedNow=initialSpeed-inertia*dTime;
						if(speedNow>minSpeed){
							scrollXWill=initialScrollX-(int)(initialSpeed*dTime-inertia*dTime*dTime/2);
							//scrollXWill=initialScrollX-(int)((initialSpeed-(inertia*dTime)/2)*dTime);
							if(scrollXWill<scrollXSaved){
								if(scrollXWill<=0){
									scrollX=0;
									scrollY=initialScrollY;
									postInvalidate();
									return;
								}
								scrollX=scrollXWill;
								scrollY=initialScrollY;
								postInvalidate();
							}
							scrollXSaved=scrollXWill;
						}else{
							break;
						}
					}
				}else{
					return;
				}
			}else if(orientation==1){
				if(initialSpeed<0){
					try{
						sleep(2);
					}catch(Exception e){}
					int scrollYSaved=initialScrollY;
					while(!interrupted()){
						dTime=System.currentTimeMillis()-initialTime;
						double speedNow=initialSpeed+inertia*dTime;
						if(speedNow<-minSpeed){
							int scrollYWill=initialScrollY-(int)(initialSpeed*dTime+inertia*dTime*dTime/2);
							//int scrollYWill=initialScrollY-(int)((initialSpeed+(inertia*dTime)/2)*dTime);
							if(scrollYWill>scrollYSaved){
								if(scrollYWill>=scrollYMaximum){
									scrollX=initialScrollX;
									scrollY=scrollYMaximum;
									postInvalidate();
									return;
								}
								scrollX=initialScrollX;
								scrollY=scrollYWill;
								postInvalidate();
							}
							scrollYSaved=scrollYWill;
						}else{
							break;
						}
					}
				}else if(initialSpeed>0){
					try{
						sleep(1);
					}catch(Exception e){}
					int scrollYSaved=initialScrollY;
					while(!interrupted()){
						dTime=System.currentTimeMillis()-initialTime;
						double speedNow=initialSpeed-inertia*dTime;
						if(speedNow>minSpeed){
							int scrollYWill=initialScrollY-(int)((initialSpeed-(inertia*dTime)/2)*dTime);
							if(scrollYWill<scrollYSaved){
								if(scrollYWill<=0){
									scrollX=initialScrollX;
									scrollY=0;
									postInvalidate();
									return;
								}
								scrollX=initialScrollX;
								scrollY=scrollYWill;
								postInvalidate();
							}
							scrollYSaved=scrollYWill;
						}else{
							break;
						}
					}
				}else return;
			}else return;
		}
	}
	class WaitLongClick extends Thread{
		int interval=400;
		Point touch=new Point();
		boolean waited=false;
		@Override
		public void run(){
			super.run();
			try{
				sleep(interval);
			}catch(Exception e){}
			if(waited){
				return;
			}else{
				waited=true;
			}
		}
	}
}
